package com.billionsfinance.crs.common.websocket;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * @ FileName: OnlineStateWebSocket.java
 * @ Author: WeiHui-Z
 * @ Date: 2017/4/22 10:26
 * @ Version: v1.0.0
 */
//该注解用来指定一个URI，客户端可以通过这个URI来连接到WebSocket。类似Servlet的注解mapping。无需在web.xml中配置。
@ServerEndpoint(value="/onlineWebsocket",configurator=GetHttpSessionConfigurator.class)
public class OnlineStateWebSocket {
    private static final Logger LOG = LoggerFactory.getLogger(OnlineStateWebSocket.class);

    //静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount = 0;

    //concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话，可以使用Map来存放，其中Key可以为用户标识
    private static CopyOnWriteArraySet<OnlineStateWebSocket> webSocketSet = new CopyOnWriteArraySet<OnlineStateWebSocket>();

    //用来存放 sim 卡号对应的 连接 session 的map  ,key 为sim 卡号,value 为各个终端的session 对象
    private static ConcurrentHashMap<String,ArrayList<OnlineStateWebSocket>> simSessionWebSocketMap = new ConcurrentHashMap<String,ArrayList<OnlineStateWebSocket>>();

    //用来存放 httpSessionId/session 的map  ,key 为httpSessionId ,value 为各个终端的session 对象
    private static ConcurrentHashMap<String,OnlineStateWebSocket> httpSessionWebSocketMap = new ConcurrentHashMap<String,OnlineStateWebSocket>();


    //与某个客户端的连接会话，需要通过它来给客户端发送数据
    private Session session;

    private HttpSession httpSession;

    /**
     * 连接建立成功调用的方法
     * @param session  可选的参数。session为与某个客户端的连接会话，需要通过它来给客户端发送数据
     */
    @OnOpen
    public void onOpen(Session session, EndpointConfig config){
        this.session = session;
        webSocketSet.add(this);     //加入set中
        addOnlineCount();           //在线数加1

        this.httpSession = (HttpSession) config.getUserProperties()
                .get(HttpSession.class.getName());
        //用于共享 httpSession
        httpSessionWebSocketMap.put(this.httpSession.getId(), this);


        System.out.println("实时数据:有新连接加入！当前在线人数为" + getOnlineCount());
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(){
        webSocketSet.remove(this);  //从set中删除
        subOnlineCount();           //在线数减1

        Set<Entry<String,ArrayList<OnlineStateWebSocket>>> entrySet = simSessionWebSocketMap.entrySet();

        Iterator<Entry<String, ArrayList<OnlineStateWebSocket>>> iterator = entrySet.iterator();
        while(iterator.hasNext()){

            Entry<String, ArrayList<OnlineStateWebSocket>> next = iterator.next();

            String key = next.getKey();    //获取sim卡号

            ArrayList<OnlineStateWebSocket> value = next.getValue(); //获取sim卡号对应的 连接的websocket终端

            if(value.contains(this)){
                if(value.size()>1){
                    value.remove(this);
                    simSessionWebSocketMap.replace(key, value);
                }else{
                    simSessionWebSocketMap.remove(key);
                }

            }
        }

        System.out.println("实时数据:有一连接关闭！当前在线人数为" + getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     * @param message 客户端发送过来的消息
     * @param session 可选的参数
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("实时数据:来自客户端的消息:" + message);

        String[] SimArray = message.split(",");

        this.session = session;
        webSocketSet.add(this);     //加入set中

        for(String sim:SimArray){

            ArrayList<OnlineStateWebSocket> vehicleClientList ;

            if(simSessionWebSocketMap.get(sim.trim()) != null){
                vehicleClientList=simSessionWebSocketMap.get(sim.trim());   //取出当前sim 卡号所对应的所有session

                vehicleClientList.add(this);
                simSessionWebSocketMap.replace(sim.trim(), vehicleClientList);
            }else{
                vehicleClientList= new ArrayList<OnlineStateWebSocket>();
                vehicleClientList.add(this);

                simSessionWebSocketMap.put(sim.trim(), vehicleClientList);
            }

        }

    }

    /**
     * 发生错误时调用
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error){
        System.out.println("实时数据:发生错误");
        error.printStackTrace();
    }

    /**
     * 这个方法与上面几个方法不一样。没有用注解，是根据自己需要添加的方法。
     * @param message
     * @throws IOException
     */
    public   void sendMessage(String message,HttpServletRequest request) throws IOException {
        if(this.session.isOpen()){
            this.session.getBasicRemote().sendText(message);
            this.session.setMaxTextMessageBufferSize(102400);
//          this.session.getAsyncRemote().sendText(message);
        }

    }

    public   void sendMessage(String message) throws IOException{

        if(this.session.isOpen()){
            this.session.getBasicRemote().sendText(message);
            this.session.setMaxTextMessageBufferSize(102400);
//          this.session.getAsyncRemote().sendText(message);
        }
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        OnlineStateWebSocket.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        OnlineStateWebSocket.onlineCount--;
    }

    public static CopyOnWriteArraySet<OnlineStateWebSocket> getWebSocketSet() {
        return webSocketSet;
    }

    public static void setWebSocketSet(CopyOnWriteArraySet<OnlineStateWebSocket> webSocketSet) {
        OnlineStateWebSocket.webSocketSet = webSocketSet;
    }



}
